#include "helper.h"
#include "monitor.h"
#include "reg.h"

extern uint32_t instr;
extern char assembly[80];

/* decode R-type instrucion */
static void decode_r_type(uint32_t instr) {

	op_src1->type = OP_TYPE_REG;
	op_src1->reg = (instr & RS_MASK) >> (RT_SIZE + IMM_SIZE);
	op_src1->val = reg_w(op_src1->reg);
	
	op_src2->type = OP_TYPE_REG;
	op_src2->imm = (instr & RT_MASK) >> (RD_SIZE + SHAMT_SIZE + FUNC_SIZE);
	op_src2->val = reg_w(op_src2->reg);

	op_dest->type = OP_TYPE_REG;
	op_dest->reg = (instr & RD_MASK) >> (SHAMT_SIZE + FUNC_SIZE);
}

make_helper(and) {
	decode_r_type(instr);
	reg_w(op_dest->reg) = (op_src1->val & op_src2->val);
	sprintf(assembly, "AND %s, %s, %s", REG_NAME(op_dest->reg), REG_NAME(op_src1->reg), REG_NAME(op_src2->reg));
}

make_helper(add) {

	decode_r_type(instr);
	int temp = (int)(op_src1->val) + (int)(op_src2->val);
	if (((int)op_src1->val > 0 && (int)op_src2->val > 0 && temp < 0) || ((int)op_src1->val < 0 && (int)op_src2->val < 0 && temp > 0)) {
		// TODO exception
		if (cpu.cp0.status.EXL == 0) { // 如果此时异常级为0，即还未有异常发生（不支持嵌套异常）
			cpu.cp0.cause.ExcCode = Ov; // 记录发生了溢出异常
			cpu.cp0.EPC = cpu.pc; // 存放异常返回地址（由软件实现具体的返回地址）
			cpu.pc = TRAP_ADDR; // 跳转到异常处理程序地址。ATTENTION!
			cpu.cp0.status.EXL = 1; // 记录已有异常发生
		}
	}else {
		reg_w(op_dest->reg) = temp;
	}
	sprintf(assembly, "add   %s,   %s,   %s", REG_NAME(op_dest->reg), REG_NAME(op_src1->reg), REG_NAME(op_src2->reg));
}

make_helper(addu) {

	decode_r_type(instr);
	reg_w(op_dest->reg) = op_src1->val + op_src2->val;
	sprintf(assembly, "addu   %s,   %s,   %s", REG_NAME(op_dest->reg), REG_NAME(op_src1->reg), REG_NAME(op_src2->reg));
}

make_helper(or) {
	decode_r_type(instr);
	reg_w(op_dest->reg) = (op_src1->val) | (op_src2->val);
	sprintf(assembly, "or   %s,   %s,   %s", REG_NAME(op_dest->reg), REG_NAME(op_src1->reg), REG_NAME(op_src2->reg));
}

make_helper(xor) {
	decode_r_type(instr);
	reg_w(op_dest->reg) = (op_src1->val) ^ (op_src2->val);
	sprintf(assembly, "xor   %s,   %s,   %s", REG_NAME(op_dest->reg), REG_NAME(op_src1->reg), REG_NAME(op_src2->reg));
}

make_helper(sllv) {
	decode_r_type(instr);
	reg_w(op_dest->reg) = (op_src2->val) << (op_src1->val); 
	sprintf(assembly, "sllv   %s,   %s,   %s", REG_NAME(op_dest->reg), REG_NAME(op_src2->reg), REG_NAME(op_src1->reg));
}

make_helper(sll) {
    decode_r_type(instr);
    uint32_t sa = (instr & SHAMT_MASK) >> FUNC_SIZE;
    reg_w(op_dest->reg) = op_src2->val << sa;
    sprintf(assembly, "sll   %s,   %s,   %u", REG_NAME(op_dest->reg), REG_NAME(op_src2->reg), sa);
}